#include "matrix.h"
#include "thread.h"

/* default register value*/
#define DEFAULT_PSR         0x01000000U
#define DEFAULT_PRIMASK     0x00000000U
#define DEFAULT_FAULTMASK   0x00000000U
#define DEFAULT_BASEPRI     0x00000000U
#define DEFAULT_CONTROL     0x00000000U
#define EXCEPTION_LR        0xFFFFFFF9U


mx_void_pt mx_thread_stack_init (mx_void_pt stack, mx_usize_t size, mx_thread_entry_t entry,
                                 mx_thread_boot_t boot, mx_thread_pt thread)
{
    mx_void_pt stack_bottom = (mx_void_pt)((mx_uint32_t)stack + size);
    mx_uint32_pt sp = (mx_uint32_pt)stack_bottom;

    /* FIXME: CCR.STKALIGN control the align of stack, We should follow it if it is not default value.
       So that this thread can be restore by `exception exit sequence` the hardware do */
    /* self-definition region, this part save at the stack bottom, a fixed address */
    *(--sp) = (mx_uint32_t)EXCEPTION_LR;        // EXC_RETURN, for interrupt
    *(--sp) = (mx_uint32_t)4;                   // R4
    *(--sp) = (mx_uint32_t)5;                   // R5
    *(--sp) = (mx_uint32_t)6;                   // R6
    *(--sp) = (mx_uint32_t)7;                   // R7
    *(--sp) = (mx_uint32_t)8;                   // R8
    *(--sp) = (mx_uint32_t)9;                   // R9
    *(--sp) = (mx_uint32_t)10;                  // R10
    *(--sp) = (mx_uint32_t)11;                  // R11
    *(--sp) = (mx_uint32_t)(sp - 13);           // R13 SP, = stack top
    *(--sp) = (mx_uint32_t)DEFAULT_PRIMASK;     // PRIMASK
    *(--sp) = (mx_uint32_t)DEFAULT_FAULTMASK;   // FAULTMASK
    *(--sp) = (mx_uint32_t)DEFAULT_BASEPRI;     // BASEPRI
    *(--sp) = (mx_uint32_t)DEFAULT_CONTROL;     // CONTROL
    /* hardware-auto-save region, this part save at the stack top, a change of address, support restore from `exception exit sequence` */
    *(--sp) = (mx_uint32_t)DEFAULT_PSR;         // xPSR
    *(--sp) = (mx_uint32_t)boot;                // PC
    *(--sp) = (mx_uint32_t)13;                  // LR
    *(--sp) = (mx_uint32_t)12;                  // R12
    *(--sp) = (mx_uint32_t)3;                   // R3
    *(--sp) = (mx_uint32_t)2;                   // R2
    *(--sp) = (mx_uint32_t)1;                   // R1
    *(--sp) = (mx_uint32_t)thread;              // R0
    return stack_bottom;
}
